GAS環境和瀏覽器與Node.js一樣,有它獨有的全域物件,可以透過globalThis呼叫。有趣的是,
globalThis
被納入ES標準與GAS轉用V8引擎,都是在2020年。
昨天(Day02)聊到,目前Google Apps Script這個環境上執行的JavaScript,與瀏覽器環境或Node.js環境上執行的JavaScript一樣,都是在V8引擎上運行。
由於環境不同,GAS環境的全域物件也與瀏覽器和Node.js不同。這篇文章打算稍微回顧JavaScript全域物件的歷史,還有GAS特有的全域物件。
我剛開始寫JavaScript的時候,只粗略知道在瀏覽器環境的全域物件是window
,而Node.js是global
。在剛接觸GAS環境時,通常直接呼叫SpreadsheetApp
,也沒特別去了解GAS的全域物件,直到遇到問題而查找資料時,才發現早年還是Rhino引擎的時候,只能透過this
指向全域物件[^1];而在我寫GAS專案時,則已經是V8時代,並支援globalThis
。
它始於ECMAScript 2020標準,用來統一不同宿主環境的全域物件入口點,能以一致方式取得全域物件。換言之,對於寫JavaScript語言的人而言,比較直觀的是,globalThis
成為正式的全域變數的官方名稱,而window
、global
、self
等則成為別名。
這個標準出來後,雖然對於沒有大型開發經驗的我個人而言感受不大,但在單元測試等場景,減少了很多為了跨環境取得全域物件而寫的boilerplate。[^2]
總之,V8時代的GAS環境的全域物件沒有別名,就是globalThis
。這裡附上Google Apps Script環境特有的全域物件之大致架構:
globalThis
├─ Google Workspace
│ ├─ SpreadsheetApp / DocumentApp / SlidesApp
│ ├─ FormApp / GmailApp / CalendarApp
│ └─ DriveApp
├─ Google其它服務
│ ├─ LanguageApp
│ ├─ Maps
│ └─ MailApp
└─ GAS平台服務
├─ UrlFetchApp / Utilities
├─ PropertiesService / CacheService / LockService
├─ ScriptApp / Session / Logger / console
└─ HtmlService / ContentService / Charts
會寫這篇文章,主要是想聊聊GAS環境和其他環境的JavaScript差異,但聊這個其實對於如何寫GAS專案沒太大幫助,僅僅是我個人對於JavaScript生態系的好奇,包含GAS當初設計時的可能脈絡。有趣的是,globalThis被納入ES標準與GAS轉用V8引擎,都是在2020年。
可能知道這個歷史脈絡唯一的效用是,查找資料時看到試著用 this
取得或設置為全域物件,可以判讀那是Rhino時代的做法。例如我個人最近在選用開源庫時,看到let global = this
而判讀是舊方案。[^3]
比較要注意的是,跟瀏覽器和Node.js不同,使用GAS特有全域物件時,大部分都是service call / RPC,會大幅影響效能,並且有quota限制。[^4]
[^1]: 更精確地說,其實是指向「隱含又特殊的context」,而非真正的global物件。詳見官方文件。
[^2]: https://v8.dev/features/globalthis
[^3]: https://github.com/mahaker/esbuild-gas-plugin
[^4]: https://developers.google.com/apps-script/guides/services/quotas